﻿//***************************************************************
// 类名：资源管理器
// 责任人：钟汶洁
// 修改日期：2015.7
// 功能：下载资源包、管理资源包的依赖关系、读取资源
//***************************************************************

using UnityEngine;
#if UNITY_EDITOR	
using UnityEditor;
#endif
using System.Collections;
using System.Collections.Generic;
using Mono.Xml;
using System.Security;

public partial class AssetBundleManager : Kernel<AssetBundleManager>
{
    const string m_RemoteAssetBundleUrl = "http://114.119.45.114/"; // 资源服务器地址

    WWW m_DownloadingAssetRecordWWW = null; // 下载资源记录文件的WWW

    /// <summary>
    /// 初始化
    /// </summary>
    /// <returns>初始化监视器</returns>
    public AssetBundleInitializeOperation Initialize()
    {
        m_LocalAssetBundleRootPath = "";
        m_RemoteAssetBundleRootPath = "";
        m_AssetBundleManifest = null;
        m_AssetRecords.Clear();
        m_AssetBundleInfos.Clear();
        m_LoadedAssetBundles.Clear();
        m_DownloadingWWWs.Clear();
        m_DownloadingErrors.Clear();
        m_InProgressOperations.Clear();
        m_Dependencies.Clear();
        m_DownloadingAssetRecordWWW = null;

        // 不同平台下资源包所在的目录名
        string platformFolderForAssetBundles = "";
#if UNITY_EDITOR
        platformFolderForAssetBundles = GetPlatformFolderForAssetBundles(EditorUserBuildSettings.activeBuildTarget);
#else
        platformFolderForAssetBundles = GetPlatformFolderForAssetBundles(Application.platform);
#endif
        // 本地资源包根路径
        m_LocalAssetBundleRootPath = GetLocalAssetBundlesPath(platformFolderForAssetBundles);

        // 创建初始化监视器，以便监视初始化完成情况
        bool isNeedDownloadAssetBundles;
#if UNITY_EDITOR
        if (SimulateAssetBundleInEditor)
        {
            isNeedDownloadAssetBundles = false;
        }
        else
#endif
        {
            isNeedDownloadAssetBundles = true;
            if (m_RemoteAssetBundleUrl.EndsWith("/"))
            {
                m_RemoteAssetBundleRootPath = string.Format("{0}{1}/", m_RemoteAssetBundleUrl, platformFolderForAssetBundles);
            }
            else
            {
                m_RemoteAssetBundleRootPath = string.Format("{0}/{1}/", m_RemoteAssetBundleUrl, platformFolderForAssetBundles);
            }
        }

        AssetBundleInitializeOperation operation = new AssetBundleInitializeOperation(platformFolderForAssetBundles, false);
        m_InProgressOperations.Add(operation);
        return operation;
    }

    /// <summary>
    /// 加载资源清单
    /// </summary>
    public string LoadAssetBundleManifest(bool isLocal)
    {
#if UNITY_EDITOR
        // 如果是在编辑器中模拟资源包的加载模式，那么不需要加载资源包清单
        if (SimulateAssetBundleInEditor)
        {
            return null;
        }
#endif
        // 资源包清单名
        string manifestName = "";
#if UNITY_EDITOR
        manifestName = GetPlatformFolderForAssetBundles(EditorUserBuildSettings.activeBuildTarget);
#else
        manifestName = GetPlatformFolderForAssetBundles(Application.platform);
#endif
        // 已经存在加载该资源包的WWW对象了，那么什么也不需要做，等待其加载完毕就OK
        if (m_DownloadingWWWs.ContainsKey(manifestName))
        {
            return null;
        }

        WWW download;
        if (isLocal)
        {
            download = new WWW(string.Format("{0}{1}", m_LocalAssetBundleRootPath, manifestName));
        }
        else
        {
            download = new WWW(string.Format("{0}{1}", m_RemoteAssetBundleRootPath, manifestName));
        }

        m_DownloadingWWWs.Add(manifestName, download);
        return manifestName;
    }

    /// <summary>
    /// 释放资源清单
    /// </summary>
    public void UnloadAssetBundleManifest()
    {
        string manifestName;
#if UNITY_EDITOR
        manifestName = GetPlatformFolderForAssetBundles(EditorUserBuildSettings.activeBuildTarget);
#else
        manifestName = GetPlatformFolderForAssetBundles(Application.platform);
#endif
        string error;
        LoadedAssetBundle bundle = GetLoadedAssetBundle(manifestName, out error);
        if (bundle == null)
        {
            return;
        }
        if (--bundle.m_ReferencedCount == 0)
        {
            bundle.m_AssetBundle.Unload(false);
            m_LoadedAssetBundles.Remove(manifestName);
        }
    }

    /// <summary>
    /// 远程资源清单加载完毕的事件
    /// </summary>
    /// <param name="manifest">资源清单</param>
    public void OnRemoteAssetBundleManifestDownloaded(AssetBundleManifest manifest)
    {
        m_AssetBundleManifest = manifest;
        string[] assetBundleNames = manifest.GetAllAssetBundles();
        for (int i = 0; i < assetBundleNames.Length; ++i)
        {
            AssetBundleInfo info;
            if (m_AssetBundleInfos.ContainsKey(assetBundleNames[i]))
            {
                info = m_AssetBundleInfos[assetBundleNames[i]];
                info.assetBundlePath = string.Format("{0}{1}", m_RemoteAssetBundleRootPath, assetBundleNames[i]);
                info.assetBundleHash = m_AssetBundleManifest.GetAssetBundleHash(assetBundleNames[i]);
            }
            else
            {
                info = new AssetBundleInfo();
                info.assetBundleName = assetBundleNames[i];
                info.assetBundlePath = string.Format("{0}{1}", m_RemoteAssetBundleRootPath, assetBundleNames[i]);
                info.assetBundleHash = m_AssetBundleManifest.GetAssetBundleHash(assetBundleNames[i]);
                m_AssetBundleInfos.Add(assetBundleNames[i], info);
            }
        }
    }

    /// <summary>
    /// 本地资源清单加载完毕的事件
    /// </summary>
    /// <param name="manifest">资源清单</param>
    public void OnLocalAssetBundleManifestDownloaded(AssetBundleManifest manifest)
    {
        m_AssetBundleManifest = manifest;
        m_AssetBundleInfos.Clear();
        if (m_AssetBundleManifest != null)
        {
            string[] assetBundleNameArray = m_AssetBundleManifest.GetAllAssetBundles();
            for (int i = 0; i < assetBundleNameArray.Length; ++i)
            {
                AssetBundleInfo info = new AssetBundleInfo();
                info.assetBundleName = assetBundleNameArray[i];
                info.assetBundlePath = string.Format("{0}{1}", m_LocalAssetBundleRootPath, assetBundleNameArray[i]);
                info.assetBundleHash = m_AssetBundleManifest.GetAssetBundleHash(assetBundleNameArray[i]);
                m_AssetBundleInfos.Add(assetBundleNameArray[i], info);
            }
        }
    }

    /// <summary>
    /// 加载资源记录文件
    /// </summary>
    /// <param name="isLocal">true：本地资源记录文件；false：远程资源记录文件</param>
    public void DownloadAssetRecord(bool isLocal)
    {
#if UNITY_EDITOR
        if (SimulateAssetBundleInEditor && IsUnRecordSimulate)
        {
            // 编辑器中模拟资源包的加载
            LoadAssetRecordsByLocal();
            return;
        }
#endif

        StartCoroutine(LoadAssetRecord(isLocal));
    }

    /// <summary>
    /// 获取到指定资源包的信息数据
    /// </summary>
    /// <param name="assetBundleName">资源包名</param>
    /// <returns>资源包信息</returns>
    public AssetBundleInfo GetAssetBundleInfo(string assetBundleName)
    {
        if (m_AssetBundleInfos == null)
        {
            return null;
        }
        if (!m_AssetBundleInfos.ContainsKey(assetBundleName))
        {
            return null;
        }
        return m_AssetBundleInfos[assetBundleName];
    }

    /// <summary>
    /// 资源记录文件是否加载成功？
    /// </summary>
    /// <returns>true：是；false：否</returns>
    public bool IsAssetRecordLoaded()
    {
        if (m_AssetRecords.Count != 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    /// <summary>
    /// 是否正在加载资源记录文件中？
    /// </summary>
    /// <returns>true：是；false：否</returns>
    public bool IsLoadingAssetRecord()
    {
        return m_DownloadingAssetRecordWWW == null ? false : true;
    }

    /// <summary>
    /// 加载资源记录文件
    /// </summary>
    /// <param name="isLocal"></param>
    /// <returns></returns>
    IEnumerator LoadAssetRecord(bool isLocal)
    {
        m_AssetRecords.Clear();

        if (m_DownloadingAssetRecordWWW != null)
        {
            Debug.LogError("The www is running to download asset record!");
            yield break;
        }

        string assetRecordFileUrl;
        if (isLocal)
        {
            assetRecordFileUrl = string.Format("{0}AssetRecord.xml", m_LocalAssetBundleRootPath);
        }
        else
        {
            assetRecordFileUrl = string.Format("{0}AssetRecord.xml", m_RemoteAssetBundleRootPath);
        }

        m_DownloadingAssetRecordWWW = new WWW(assetRecordFileUrl);

        yield return m_DownloadingAssetRecordWWW;
        if (!string.IsNullOrEmpty(m_DownloadingAssetRecordWWW.error))
        {
            Debug.LogError(m_DownloadingAssetRecordWWW.error);
            m_DownloadingAssetRecordWWW = null;
            yield break;
        }

        string assetRecordXml = m_DownloadingAssetRecordWWW.text;
        SecurityElement root;
        try
        {
            SecurityParser sp = new SecurityParser();
            sp.LoadXml(assetRecordXml);
            root = sp.ToXml();
        }
        catch
        {
            m_DownloadingAssetRecordWWW = null;
            Debug.LogError("Failed to read 'AssetRecord.xml'!");
            yield break;
        }
        foreach (SecurityElement child in root.Children)
        {
            SecurityElement assetName = child.SearchForChildByTag("Name");
            SecurityElement assetBundleName = child.SearchForChildByTag("AssetBundle");

            if (assetName == null || assetBundleName == null)
            {
                Debug.LogError("'AssetRecord.xml' has error!");
                continue;
            }
            if (m_AssetRecords.ContainsKey(assetName.Text))
            {
                Debug.LogError(string.Format("The asset recode xml has a same key [{0}]!", assetName.Text));
                continue;
            }


            m_AssetRecords.Add(assetName.Text, assetBundleName.Text);
        }
        m_DownloadingAssetRecordWWW = null;
    }
#if UNITY_EDITOR
    void LoadAssetRecordsByLocal()
    {
        string[] paths = AssetDatabase.GetAllAssetPaths();
        for (int i = 0; i < paths.Length; i++)
        {
            string path = paths[i];
            if (path.Contains("Primitives"))
            {
                if (path.EndsWith(".prefab")
                    || path.EndsWith(".bytes")
                    || path.EndsWith(".asset")
                    || path.EndsWith(".wav")
                    || path.EndsWith(".mp3")
                    || path.EndsWith(".anim")
                    || path.EndsWith(".controller"))
                {
                    string fileName = path.Substring(path.LastIndexOf("/") + 1);
                    string name = fileName.Substring(0, fileName.IndexOf("."));

                    if (m_AssetRecords.ContainsKey(name))
                    {
                        Debug.LogErrorFormat("AssetBundle name[{0}] was repeated please use different name !", name);
                    }
                    m_AssetRecords[name] = path;
                }
            }
            else if(path.Contains("Scenes")) // 增加场景
            {
                if (path.EndsWith(".unity"))
                {
                    string fileName = path.Substring(path.LastIndexOf("/") + 1);
                    string name = fileName.Substring(0, fileName.IndexOf("."));

                    if (m_AssetRecords.ContainsKey(name))
                    {
                        Debug.LogErrorFormat("AssetBundle name[{0}] was repeated please use different name !", name);
                    }
                    m_AssetRecords[name] = path;
                }
            }
        }
    }

#endif
}
